package com.snap.update.widget;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;

public class DnaLoading extends View {

    private static final String TAG = "DnaLoading";

    private Resources mResources;

    private float ratio = 3f;
    private int mDefaultWidth = 200;
    private int mDefaultHeight = (int) (mDefaultWidth / ratio);

    private int mRowWidth;//每列的宽度  也是圆心距
    private int mRowCount = 11;
    private double delta = Math.PI * 2 / (mRowCount - 1);//相位差

    private int mTotalWidth;
    private int mTotalHeight;
    private int mYAmp;

    private float mRadiusMax;
    private float mRadiusMin;
    private float mRadiusBase;
    private float mRadiusAmp;

    private int colorPrimary = 0xff044ea1;
    private int colorBlueDark = 0xff34acda;
    private int colorBlueLight = 0xff9fd9f6;

    private Paint mMainPaint;
    private Paint mOtherPaint;

    private ValueAnimator mAnimator;
    private float mFactor;

    public DnaLoading(Context context) {
        super(context);
        init(context);
    }

    public DnaLoading(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mResources = getResources();
        mDefaultWidth = dp2px(mDefaultWidth);
        mDefaultHeight = dp2px(mDefaultHeight);

        //init paint
        mMainPaint = new Paint();
        mMainPaint.setAntiAlias(true);

        mOtherPaint = new Paint();
        mOtherPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ViewGroup.LayoutParams params = this.getLayoutParams();
        int measureWidth = getMeasureWidth(widthMeasureSpec, params);
        int measureHeight = getMeasureHeight(heightMeasureSpec, params);
        //按比例重置宽高 按小一边的取值
        measureWidth = measureWidth > measureHeight * ratio ? (int) (measureHeight * ratio) : measureWidth;
        measureHeight = (int) (measureWidth / ratio);
        //自定义宽高
        setMeasuredDimension(measureWidth, measureHeight);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mTotalWidth = w > h * ratio ? (int) (h * ratio) : w;
        mTotalHeight = (int) (mTotalWidth / ratio);

        mRowWidth = mTotalWidth / mRowCount;

        mRadiusMin = mRowWidth / 5.5f;
        mRadiusMax = mRadiusMin * 2f;
        mRadiusAmp = (mRadiusMax - mRadiusMin) / 2;
        mRadiusBase = (mRadiusMax + mRadiusMin) / 2;

        mYAmp = (int) (mTotalHeight - 2 * mRadiusMax);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < mRowCount; i++) {
            double φ = (i % (mRowCount - 1)) * delta - Math.PI * 2 * mFactor;
            double cosValue = Math.cos(φ);
            float cx = i * mRowWidth + mRowWidth / 2f;
            float cy = (float) (mRadiusMax + (1 - cosValue) * mYAmp / 2);
            float radius = (float) (mRadiusBase + cosValue * mRadiusAmp);
            double percent = (1 - cosValue) / 2 * 0.3f;
            int color = mixColor(colorPrimary, Color.WHITE, percent);
            mMainPaint.setColor(color);

            float cy2 = mTotalHeight - cy;
            float radius2 = (float) (mRadiusBase - cosValue * mRadiusAmp);
            double percent2 = (1 - cosValue) / 2;
            int color2 = mixColor(colorBlueLight, colorBlueDark, percent2);
            mOtherPaint.setColor(color2);

//            canvas.drawLine(cx, cy, cx, cy2, mMainPaint);//最简陋的氢键
            // 高端一点的氢键 粗细 颜色渐变  粗的一端永远跟着主粒子
            // 再配合一些画布的旋转
            if (Math.sin(φ) > 0) {
                canvas.drawCircle(cx, cy, radius, mMainPaint);
                canvas.drawCircle(cx, cy2, radius2, mOtherPaint);
            } else {
                canvas.drawCircle(cx, cy2, radius2, mOtherPaint);
                canvas.drawCircle(cx, cy, radius, mMainPaint);
            }
        }
    }

    /**
     * //第2颜色掺入第1颜色
     *
     * @param color1  主色
     * @param color2  辅助色
     * @param percent 掺入的比例
     * @return 颜色
     */
    private int mixColor(int color1, int color2, double percent) {
        int R = (int) (Color.red(color1) + (Color.red(color2) - Color.red(color1)) * percent);
        int G = (int) (Color.green(color1) + (Color.green(color2) - Color.green(color1)) * percent);
        int B = (int) (Color.blue(color1) + (Color.blue(color2) - Color.blue(color1)) * percent);
        return Color.rgb(R, G, B);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Animator animator = getAnim();
        if (!animator.isRunning())
            animator.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Animator animator = getAnim();
        if (animator.isRunning())
            animator.cancel();
    }

    //debug用
    public void switchAnimate() {
        Animator animator = getAnim();
        if (animator.isPaused())
            animator.resume();
        else
            animator.pause();
    }

    public Animator getAnim() {
        if (mAnimator != null) return mAnimator;
        mAnimator = ValueAnimator.ofFloat(0, 1f).setDuration(2000);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.addUpdateListener(animation -> {
            mFactor = (float) animation.getAnimatedValue();
            invalidate();
        });
        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mAnimator.setRepeatMode(ValueAnimator.RESTART);
        return mAnimator;
    }

    private int getMeasureWidth(int widthMeasureSpec, ViewGroup.LayoutParams params) {
        int measureWidth;
        if (params.width == ViewGroup.LayoutParams.MATCH_PARENT) {
            measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        } else if (params.width >= 0) {
            measureWidth = params.width;
        } else {
            measureWidth = mDefaultWidth;
        }
        return measureWidth;
    }

    private int getMeasureHeight(int heightMeasureSpec, ViewGroup.LayoutParams params) {
        int measureHeight;
        if (params.height == ViewGroup.LayoutParams.MATCH_PARENT) {
            measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        } else if (params.height >= 0) {
            measureHeight = params.height;
        } else {
            measureHeight = mDefaultHeight;
        }
        return measureHeight;
    }

    private int dp2px(float dpValue) {
        return (int) (dpValue * mResources.getDisplayMetrics().density + 0.5f);
    }
}